package com.gzhryc.common.redis;

import com.gzhryc.common.StringTools;
import com.gzhryc.common.config.PropertyTools;
import com.gzhryc.common.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Properties;
import java.util.Set;

public class RedisTools {

	static Logger log = Logger.getLogger(RedisTools.class);

	public final static Integer Timeout = 60000;
	public final static Boolean SSL = false;

	public final static Integer MaxTotal = 30; // 最大连接数
	public final static Integer MaxIdle = 8; // 最大空闲连接数
	public final static Integer MaxWaitMillis = 60000; // 最大等待时间
	public final static Boolean TestOnBorrow = true; // 检查连接可用性, 确保获取的Redis实例可用
	public final static Boolean TestOnReturn = true;

	static RedisTools self;

	public static RedisTools get() {
		if (self == null) {
			self = new RedisTools();
		}
		return self;
	}

	private Properties properties;
	private JedisPool jedisPool;

	private String host;
	private Integer port;
	private String password;

	public RedisTools() {
	}

	/**
	 * MaxTotal 连接实例的最大连接数 MaxIdle 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8
	 * MaxWaitMillis 待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException
	 * TestOnBorrow 在borrow一个Redis实例时，是否提前进行validate操作；如果为true，则得到的Redis实例均是可用的
	 * TestOnReturn 在使用前测试Redis实例
	 * 
	 * @param properties
	 */
	public void initial(Properties properties) {
		if (jedisPool != null) {
			jedisPool.destroy();
			jedisPool = null;
		}
		if (properties != null) {
			this.properties = properties;
			PropertyTools propertyTools = PropertyTools.build(properties);
			String host = propertyTools.getString("Host");
			Integer port = propertyTools.getInt("Port");
			Integer timeout = propertyTools.getInt("Timeout");
			String password = propertyTools.getString("Password");
			Boolean ssl = propertyTools.getBoolean("SSL");
			if (StringUtils.isNotBlank(host) && port != null) {
				JedisPoolConfig config = propertyTools.getObject("Pool2", JedisPoolConfig.class);
				this.host = host;
				this.port = port;
				this.password = password;
				jedisPool = new JedisPool(config, host, port, timeout, password, ssl);
			}
		}
	}

	public void initial(JedisPoolConfig config, String host, Integer port, Integer timeout, String password,
			Boolean ssl) {
		if (jedisPool != null) {
			jedisPool.destroy();
			jedisPool = null;
		}
		if (StringUtils.isNotBlank(host) && port != null) {
			this.host = host;
			this.port = port;
			this.password = password;
			jedisPool = new JedisPool(config, host, port, timeout, password, ssl);
		}
	}

	/**
	 * 使用默认值初始化
	 * 
	 * @param host
	 * @param port
	 * @param password
	 */
	public void initial(String host, Integer port, String password) {
		if (jedisPool != null) {
			jedisPool.destroy();
			jedisPool = null;
		}
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(MaxTotal);
		config.setMaxIdle(MaxIdle);
		config.setMaxWaitMillis(MaxWaitMillis);
		config.setTestOnBorrow(TestOnBorrow);
		config.setTestOnReturn(TestOnReturn);
		this.host = host;
		this.port = port;
		this.password = password;
		jedisPool = new JedisPool(config, host, port, Timeout, password, SSL);
	}

	public Jedis getJedis() {
		if (jedisPool != null) {
			try {
				return jedisPool.getResource();
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				log.error("Redis连接池错误，重置连接池");
				if (this.properties != null) {
					this.initial(this.properties);
				} else {
					this.initial(host, port, password);
				}
			}
		}
		return null;
	}

	public String get(int db, String key) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.get(key);
			} finally {
				jedis.close();
			}
		}
		return null;
	}

	public String getAndRemove(int db, String key) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				if(jedis.exists(key)){
					String str = jedis.get(key);
					jedis.del(key);
					return str;
				}
			} finally {
				jedis.close();
			}
		}
		return null;
	}

	/**
	 * 清空指定数据库
	 * 
	 * @param db
	 * @return
	 */
	public String clear(int db) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.flushDB();
			} finally {
				jedis.close();
			}
		}
		return null;
	}

	public boolean checkConfig(String host,Integer port,String password){
		if(this.host.equals(host) && this.port.equals(port)){
			if(StringTools.isBlank(this.password) || this.password.equals(password)){
				return true;
			}
		}
		return false;
	}

	/**
	 * 查询所有主键
	 * 
	 * @param db
	 * @return
	 */
	public Set<String> findKeys(int db) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.keys("*");
			} finally {
				jedis.close();
			}
		}
		return null;
	}

	public Set<String> findKeys(int db, String key) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.keys(key);
			} finally {
				jedis.close();
			}
		}
		return null;
	}

	/**
	 * 检查Key是否存在
	 * 
	 * @param db
	 * @param key
	 * @return
	 */
	public boolean exists(int db, String key) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.exists(key);
			} finally {
				jedis.close();
			}
		}
		return false;
	}

	public boolean delete(int db, String... key) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				return jedis.del(key) > 0;
			} finally {
				jedis.close();
			}
		}
		return false;
	}

	public boolean set(int db, String key, String value) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				jedis.set(key, value);
				return true;
			} finally {
				jedis.close();
			}
		}
		return false;
	}

	public boolean setnx(int db, String key, String value,Long times) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				if(jedis.setnx(key, value) == 1) {
					jedis.expire(key, times);
					return true;
				}
			} finally {
				jedis.close();
			}
		}
		return false;
	}

	/**
	 * 保存数据，并设置有效时长
	 * 
	 * @param db
	 * @param key
	 * @param value
	 * @param times 有效时间（秒）
	 */
	public boolean set(int db, String key, String value, Long times) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				jedis.set(key, value);
				jedis.expire(key, times);
				return true;
			}finally {
				jedis.close();
			}
		}
		return false;
	}

	public boolean expire(int db, String key, Long times) {
		Jedis jedis = getJedis();
		if (jedis != null) {
			try {
				jedis.select(db);
				jedis.expire(key, times);
				return true;
			} finally {
				jedis.close();
			}
		}
		return false;
	}
}
